package com.njym.payment.wxpay;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.njym.entity.PlatformBusinessRec;
import com.njym.entity.SysOrganization;
import com.njym.payment.alipay.properties.QueryRefundParams;
import com.njym.payment.wxpay.Server.WXservice;
import com.njym.payment.wxpay.Server.WxMD5Util;
import com.njym.payment.wxpay.api.Configure;
import com.njym.payment.wxpay.api.Signature;
import com.njym.payment.wxpay.api.Util;
import com.njym.payment.wxpay.api.XMLParser;
import com.njym.payment.wxpay.properties.*;
import com.njym.service.PlatformBusinessRecService;
import com.njym.service.SysOrganizationService;
import com.njym.tradeStatusConfig.WxTradeStatus;
import com.njym.util.IpUtil;
import com.njym.vo.GetSerialNumber;
import com.njym.vo.Json;
import com.njym.webservice.WebService;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.StaxDriver;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.*;
import java.math.BigDecimal;
import java.net.ConnectException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;

/**
 * @author Binary Wang
 */
@RestController
@RequestMapping("/wxpay_api")
public class WxPayController {
	private static final Logger log = LoggerFactory.getLogger(WxPayController.class);

	private GetSerialNumber getSerialNumber;

	private PlatformBusinessRecService platformBusinessRecService;

	@Autowired
	private SysOrganizationService sysOrganizationService;

	@Resource
	private GetWxPayClient wxPayClient;

	@Autowired
	private WebService webService;

	@Autowired
	private WXservice wXservice;

	public WxPayController(
		GetSerialNumber getSerialNumber, PlatformBusinessRecService platformBusinessRecService) {
		this.getSerialNumber = getSerialNumber;
		this.platformBusinessRecService = platformBusinessRecService;
	}

	private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

	private static final Random RANDOM = new SecureRandom();

	/**
	 * 池中所保存的线程数，包括空闲线程。
	 */
	private final static int CORE_POOL_SIZE = 10;

	/**
	 * 拒绝策略，都满的情况下把被拒绝的线程重新执行
	 */
	private final static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();

	private final static ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("queryRefund-pool-%d").build();

	private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(CORE_POOL_SIZE, THREAD_FACTORY, HANDLER);

	/**
	 * 生成32位随机数
	 *
	 * @return String(32)
	 */
	public static String generateNonceStr() {
		char[] nonceChars = new char[32];
		for (int index = 0; index < nonceChars.length; ++index) {
			nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
		}
		return new String(nonceChars);
	}

	/**
	 * 校验字符串是否全是数字
	 *
	 * @param str
	 * @return
	 */
	public boolean isNumeric(String str) {
		boolean flag = true;
		if (StringUtils.isNotEmpty(str)) {
			for (int i = 0; i < str.length(); i++) {
				if (!Character.isDigit(str.charAt(i))) {
					flag = false;
					break;
				}
			}
		} else {
			flag = false;
		}
		return flag;
	}

	//	@GetMapping("/myPcInfo")
	//	public Json getMyPcInfo() {
	//		String sn = getSerialNumber.getSerialNumber("C");
	//		String value = getSerialNumber.getInfo(sn);
	//		return Json.succ(value);
	//	}

	/**
	 * 查询订单支付状态
	 *
	 * @param prepayParams
	 * @return
	 */
	@ApiOperation(value = "微信查询交易状态接口", notes = "直接返回交易状态", httpMethod = "POST")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "商户生成的交易号", name = "outTradeNo", required = true, dataType = "String", example = "20190222130826711"),
	})
	@PostMapping("/queryStatus")
	public Json queryStatus(@Valid QueryRefundParams prepayParams, BindingResult bindingResult) {
		String oper = "wx_query";
		log.info("{}, body: {}", oper, prepayParams);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		String values = "";
		String tradeNo = "";
		String amount = "";
		String orgId = prepayParams.getOrgId();

		WxPayService wxService = wxPayClient.getWxService(orgId);
		WxPayOrderQueryResult wxPayOrderQueryResult;
		WxPayOrderQueryRequest wxPayOrderQueryRequest = new WxPayOrderQueryRequest();
		wxPayOrderQueryRequest.setTransactionId(prepayParams.getTransactionNo());
		wxPayOrderQueryRequest.setOutTradeNo(prepayParams.getOutTradeNo());
		try {
			wxPayOrderQueryResult = wxService.queryOrder(wxPayOrderQueryRequest);
			String returnCode = wxPayOrderQueryResult.getReturnCode();
			String resultCode = wxPayOrderQueryResult.getResultCode();
			if (WxTradeStatus.SUCCESS.equals(returnCode)) {
				if (WxTradeStatus.SUCCESS.equals(resultCode)) {
					String tradeState = wxPayOrderQueryResult.getTradeState();
					switch (tradeState) {
						case WxTradeStatus.SUCCESS:
							values = "TRADE_SUCCESS";
							tradeNo = wxPayOrderQueryResult.getTransactionId();
							PlatformBusinessRec businessRecs = platformBusinessRecService.getPlatformBusinessRecByOutTradeNo(prepayParams.getOutTradeNo());
							amount = businessRecs.getTotalFee().toString();
							if (businessRecs != null && org.apache.commons.lang.StringUtils.isBlank(businessRecs.getTradeNo())) {
								businessRecs.setTradeStatus(WxPayConstants.WxpayTradeStatus.SUCCESS);
								businessRecs.setTradeNo(tradeNo);
								platformBusinessRecService.updateById(businessRecs);
							}
							break;
						case WxTradeStatus.USERPAYING:
							values = "TRADE_PAYING";
							break;
						case WxTradeStatus.PAYERROR:
							values = "TRADE_CLOSED";
							break;
						case WxTradeStatus.NOTPAY:
							values = "TRADE_NOTPAY";
							break;
						case WxTradeStatus.REFUND:
							values = "TRADE_REFUND";
							break;
						case WxTradeStatus.CLOSED:
							values = "TRADE_CLOSED";
							break;
						case WxTradeStatus.REVOKED:
							values = "TRADE_CLOSED";
							break;
						default:
							values = "QUERY_FAILURE";
					}
				}
			} else {
				values = "QUERY_FAILURE";
			}
		}
		catch (WxPayException e) {
			values = "QUERY_FAILURE";
		}
		return Json.succ(true, oper, values, tradeNo).data("fee", amount);
	}

	/**
	 * <pre>
	 * 提交刷卡支付.
	 * 文档地址：https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
	 * 应用场景：
	 * 收银员使用扫码设备读取微信用户刷卡授权码以后，二维码或条码信息传送至商户收银台，由商户收银台或者商户后台调用该接口发起支付。
	 * 提醒1：提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时，商户系统等待5秒后调用【查询订单API】，查询支付实际交易结果；当返回结果为“USERPAYING”时，商户系统可设置间隔时间(建议10秒)重新查询支付结果，直到支付成功或超时(建议30秒)；
	 * 提醒2：在调用查询接口返回后，如果交易状况不明晰，请调用【撤销订单API】，此时如果交易失败则关闭订单，该单不能再支付成功；如果交易成功，则将扣款退回到用户账户。当撤销无返回或错误时，请再次调用。注意：请勿扣款后立即调用【撤销订单API】,建议至少15秒后再调用。撤销订单API需要双向证书。
	 * 接口地址：   https://api.mch.weixin.qq.com/pay/micropay
	 * 是否需要证书：不需要。
	 * </pre>
	 */
	@ApiOperation(value = "条码支付接口", notes = "收银员使用扫码设备读取微信用户刷卡授权码以后，二维码或条码信息传送至商户收银台，由商户收银台或者商户后台调用该接口发起支付", httpMethod = "POST")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "渠道ID", name = "channelId", required = true, dataType = "String", example = "1034683401866588162"),
		@ApiImplicitParam(value = "系统订单号", name = "outTradeNo", required = true, dataType = "String", example = "1111111141111"),
		@ApiImplicitParam(value = "有效时间，格式为yyyyMMddHHmmss，如2009年12月27日9点10分10秒表示为20091227091010。注意：最短失效时间间隔需大于1分钟", name = "expireTime", required = false, dataType = "String", example = "15"),
		@ApiImplicitParam(value = "支付授权码；注：用户刷卡条形码规则：18位纯数字，以10、11、12、13、14、15开头", name = "authCode", required = true, dataType = "String", example = "1111111141111"),
		@ApiImplicitParam(value = "病人卡号", name = "cardNo", required = false, dataType = "String", example = "12345678", allowEmptyValue = true),
		@ApiImplicitParam(value = "病人姓名", name = "name", required = false, dataType = "String", example = "测试人1", allowEmptyValue = true),
		@ApiImplicitParam(value = "标题", name = "body", required = true, dataType = "String", example = "测试标题"),
		@ApiImplicitParam(value = "描述", name = "detail", required = true, dataType = "String", example = "测试描述"),
		@ApiImplicitParam(value = "订单总金额 单位为元，保留两位小数", name = "totalFee", required = true, dataType = "BigDecimal", example = "1.00"),
		@ApiImplicitParam(value = "商户机具终端编号", name = "deviceInfo", required = false, example = ""), @ApiImplicitParam(value = "商户操作员编号", name = "operatorId", required = true, example = "111111111"),
		@ApiImplicitParam(value = "操作员姓名", name = "operatorName", required = true, dataType = "String", example = "操作员1"),
	})
	@PostMapping("micropay")
	public Json microPay(@Valid MicroPayParams microPayParams, BindingResult bindingResult, HttpServletRequest request) {
		String oper = "wxpay_micropay";
		log.info("{}, body: {}", oper, microPayParams);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		String orgId = microPayParams.getOrgId();
		String channelId = microPayParams.getChannelId();
		String outTradeNo = microPayParams.getOutTradeNo();
		String cardNo = microPayParams.getCardNo();
		String name = microPayParams.getName();
		String operatorId = microPayParams.getOperatorId();
		String operatorName = microPayParams.getOperatorName();
		WxPayService wxService = wxPayClient.getWxService(orgId);
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}

		WxPayMicropayRequest wxPayMicropayRequest = new WxPayMicropayRequest();
		wxPayMicropayRequest.setBody(microPayParams.getBody());
		if (org.apache.commons.lang.StringUtils.isNotBlank(microPayParams.getExpireTime())) {
			wxPayMicropayRequest.setTimeExpire(microPayParams.getExpireTime());
		}
		wxPayMicropayRequest.setDetail(microPayParams.getDetail());
		wxPayMicropayRequest.setOutTradeNo(microPayParams.getOutTradeNo());
		wxPayMicropayRequest.setOutTradeNo(microPayParams.getOutTradeNo());
		String totalFee = microPayParams.getTotalFee();
		BigDecimal bd;
		Integer fee;
		try {
			bd = new BigDecimal(totalFee).setScale(2, BigDecimal.ROUND_HALF_UP);
			fee = bd.multiply(new BigDecimal(100)).intValue();
		}
		catch (Exception e) {
			return Json.fail(oper, "totalFee格式不正确！");
		}
		wxPayMicropayRequest.setTotalFee(fee);
		wxPayMicropayRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));
		String authCode = microPayParams.getAuthCode();
		boolean flag = isNumeric(authCode);
		if (flag) {
			wxPayMicropayRequest.setAuthCode(authCode);
		} else {
			return Json.fail(oper, "authCode格式错误，需重新扫码");
		}

		String resultStr;
		String tradeNo;
		try {
			WxPayMicropayResult wxPayMicropayResult = wxService.micropay(wxPayMicropayRequest);
			String returnCode = wxPayMicropayResult.getReturnCode();
			String resultCode = wxPayMicropayResult.getResultCode();
			wxPayMicropayResult.getTransactionId();
			// 处理微信条码付返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode)) {
				if (WxTradeStatus.SUCCESS.equals(resultCode)) {
					//如果直接成功，则将记录插入数据库
					resultStr = "支付成功";
					PlatformBusinessRec businessRec = new PlatformBusinessRec();
					businessRec.setOrgId(orgId);
					businessRec.setChannelId(channelId);
					businessRec.setModeId(wxPayClient.getModeById(orgId).getId());
					businessRec.setRecType(Byte.valueOf("1"));
					tradeNo = wxPayMicropayResult.getTransactionId();
					businessRec.setTradeNo(tradeNo);
					businessRec.setOutTradeNo(outTradeNo);
					businessRec.setCardNo(cardNo);
					businessRec.setName(name);
					businessRec.setTotalFee(bd);
					businessRec.setTradeStatus(WxTradeStatus.SUCCESS);
					businessRec.setTradeDate(new Date());
					businessRec.setAccountFlag(Byte.valueOf("0"));
					businessRec.setAbnormalFlag(Byte.valueOf("0"));
					businessRec.setCreateDate(new Date());
					businessRec.setOperatorId(operatorId);
					businessRec.setOperatorName(operatorName);
					platformBusinessRecService.insert(businessRec);
				} else {
					return Json.fail(oper, wxPayMicropayResult.getErrCodeDes());
				}
			} else {
				return Json.fail(oper, wxPayMicropayResult.getErrCodeDes());
			}
		}
		catch (WxPayException e) {
			if (WxTradeStatus.SUCCESS.equals(e.getReturnCode())) {
				String errCode = e.getErrCode();
				if (WxTradeStatus.USERPAYING.equals(errCode)) {
					//需要用户输入支付密码,进入轮询根据结果处理
					boolean payResult;
					try {
						JSONObject result = this.loopQueryOrder(wxService, outTradeNo);
						payResult = result.getBoolean("payResult");
						if (payResult) {
							resultStr = "支付成功";
							PlatformBusinessRec businessRec = new PlatformBusinessRec();
							businessRec.setOrgId(orgId);
							businessRec.setChannelId(channelId);
							businessRec.setModeId(wxPayClient.getModeById(orgId).getId());
							businessRec.setRecType(Byte.valueOf("1"));
							tradeNo = result.getString("tradeNo");
							businessRec.setTradeNo(tradeNo);
							businessRec.setTradeStatus(WxTradeStatus.SUCCESS);
							businessRec.setOutTradeNo(outTradeNo);
							businessRec.setCardNo(cardNo);
							businessRec.setName(name);
							businessRec.setTotalFee(bd);
							businessRec.setTradeDate(new Date());
							businessRec.setAccountFlag(Byte.valueOf("0"));
							businessRec.setAbnormalFlag(Byte.valueOf("0"));
							businessRec.setCreateDate(new Date());
							businessRec.setOperatorId(operatorId);
							businessRec.setOperatorName(operatorName);
							platformBusinessRecService.insert(businessRec);
						} else {
							return Json.fail(oper, "支付失败，请重新生成订单发起支付");
						}
					}
					catch (WxPayException e1) {
						return Json.fail(oper, e1.getErrCodeDes());
					}
				} else {
					return Json.fail(oper, e.getErrCodeDes());
				}
			} else {
				return Json.fail(oper, e.getCustomErrorMsg());
			}
		}
		return Json.succ(oper, resultStr).data("tradeNo", tradeNo);
	}

	private JSONObject loopQueryOrder(WxPayService wxPayService, String outTradeNo) throws WxPayException {
		int interval = 5000;
		int queryCount = 9;
		boolean booleanClose;
		boolean payResult;
		String tradeNo = "";
		do {
			try {
				Thread.sleep(interval);
			}
			catch (InterruptedException e) {
				e.printStackTrace();
			}
			JSONObject resultJson = this.queryOrder(wxPayService, outTradeNo);
			String result = resultJson.getString("result");
			if (WxTradeStatus.USERPAYING.equals(result)) {
				booleanClose = false;
				if (queryCount == 1) {
					booleanClose = true;
				}
				queryCount--;
				payResult = false;
			} else if (WxTradeStatus.CLOSED.equals(result)) {
				queryCount = 0;
				booleanClose = true;
				payResult = false;
			} else if (WxTradeStatus.SUCCESS.equals(result)) {
				queryCount = 0;
				booleanClose = false;
				payResult = true;
				tradeNo = resultJson.getString("tradeNo");
			} else {
				queryCount = 0;
				booleanClose = false;
				payResult = false;
			}
		} while (queryCount > 0 && !payResult);
		// 状态如果关闭
		if (booleanClose) {
			// 撤销订单
			reverseOrders(wxPayService, outTradeNo);
		}
		JSONObject resultJson = new JSONObject();
		resultJson.put("payResult", payResult);
		resultJson.put("tradeNo", tradeNo);
		return resultJson;
	}

	//	private WxPayOrderQueryResult queryWxOrder(String outTradeNo) throws WxPayException {
	//		WxPayOrderQueryResult wxPayOrderQueryResult = this.wxService.queryOrder(null, outTradeNo);
	//		return wxPayOrderQueryResult;
	//	}

	/**
	 * <pre>
	 * 查询订单 只返回订单结果
	 * 该接口提供所有微信支付订单的查询，商户可以通过查询订单接口主动查询订单状态，完成下一步的业务逻辑。
	 * 需要调用查询接口的情况：
	 * ◆ 当商户后台、网络、服务器等出现异常，商户系统最终未接收到支付通知；
	 * ◆ 调用支付接口后，返回系统错误或未知交易状态情况；
	 * ◆ 调用被扫支付API，返回USERPAYING的状态；
	 * ◆ 调用关单或撤销接口API之前，需确认支付状态；
	 * 接口地址：https://api.mch.weixin.qq.com/pay/orderquery
	 * </pre>
	 *
	 * @param outTradeNo 商户系统内部的订单号，当没提供transactionId时需要传这个。
	 */
	private JSONObject queryOrder(WxPayService wxService, String outTradeNo) {
		WxPayOrderQueryResult wxPayOrderQueryResult;
		JSONObject result = new JSONObject();
		try {
			wxPayOrderQueryResult = wxService.queryOrder(null, outTradeNo);
			String returnCode = wxPayOrderQueryResult.getReturnCode();
			String resultCode = wxPayOrderQueryResult.getResultCode();
			// 处理微信返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode)) {
				if (WxTradeStatus.SUCCESS.equals(resultCode)) {
					String tradeState = wxPayOrderQueryResult.getTradeState();
					switch (tradeState) {
						case WxTradeStatus.SUCCESS:
							result.put("result", "SUCCESS");
							result.put("tradeNo", wxPayOrderQueryResult.getTransactionId());
							break;
						case WxTradeStatus.USERPAYING:
							result.put("result", "USERPAYING");
							break;
						case WxTradeStatus.PAYERROR:

						case WxTradeStatus.NOTPAY:
							result.put("result", "CLOSE");
							break;
						case WxTradeStatus.REFUND:
						case WxTradeStatus.CLOSED:
						case WxTradeStatus.REVOKED:
							result.put("result", "FAIL");
							break;
						default:
							break;
					}
				}
			} else {
				result.put("result", "FAIL");
			}
		}
		catch (WxPayException e) {
			result.put("result", "FAIL");
		}
		return result;
	}

	/**
	 * <pre>
	 * 关闭订单
	 * 应用场景
	 * 以下情况需要调用关单接口：
	 * 1. 商户订单支付失败需要生成新单号重新发起支付，要对原订单号调用关单，避免重复支付；
	 * 2. 系统下单后，用户支付超时，系统退出不再受理，避免用户继续，请调用关单接口。
	 * 注意：订单生成后不能马上调用关单接口，最短调用时间间隔为5分钟。
	 * 接口地址：https://api.mch.weixin.qq.com/pay/closeorder
	 * 是否需要证书：   不需要。
	 * </pre>
	 *
	 * @param outTradeNo 商户系统内部的订单号
	 */
	//	public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException {
	//		WxPayOrderCloseResult orderCloseResult = this.wxService.closeOrder(outTradeNo);
	//		return orderCloseResult;
	//	}

	/**
	 * <pre>
	 * 撤销订单API
	 * 文档地址：https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
	 * 应用场景：
	 *  支付交易返回失败或支付系统超时，调用该接口撤销交易。如果此订单用户支付失败，微信支付系统会将此订单关闭；如果用户支付成功，微信支付系统会将此订单资金退还给用户。
	 *  注意：7天以内的交易单可调用撤销，其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】，没有明确的支付结果再调用【撤销订单API】。
	 *  调用支付接口后请勿立即调用撤销订单API，建议支付后至少15s后再调用撤销订单接口。
	 *  接口链接 ：https://api.mch.weixin.qq.com/secapi/pay/reverse
	 *  是否需要证书：请求需要双向证书。
	 * </pre>
	 */
	private void reverseOrders(WxPayService wxService, String outTradeNo) {
		WxPayOrderReverseRequest request = new WxPayOrderReverseRequest();
		request.setOutTradeNo(outTradeNo);
		WxPayOrderReverseResult wxPayOrderReverseResult;
		try {
			wxPayOrderReverseResult = wxService.reverseOrder(request);
			String returnCode = wxPayOrderReverseResult.getReturnCode();
			String resultCode = wxPayOrderReverseResult.getResultCode();
			// 处理微信返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode) && WxTradeStatus.SUCCESS.equals(resultCode)) {
			} else {
				//没有撤销成功的，5秒后重新撤销订单
				scheduledThreadPoolExecutor.schedule(() -> {
					reverseOrders(wxService, outTradeNo);
				}, 5, TimeUnit.SECONDS);
			}
		}
		catch (WxPayException e) {
			e.printStackTrace();
		}
	}

	@ApiOperation(value = "撤销订单", notes = "微信撤销订单", httpMethod = "POST")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "系统订单号", name = "outTradeNo", required = true, dataType = "String", example = "1111111141111"),
	})
	@PostMapping("reverseOrder")
	public Json reverseOrder(@Valid ReverseOrderParams reverseOrderParams, BindingResult bindingResult) {
		String oper = "wxpay_closeOrder";
		log.info("{}, body: {}", oper);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		WxPayService wxService = wxPayClient.getWxService(reverseOrderParams.getOrgId());
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}
		WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
		request.setOutTradeNo(reverseOrderParams.getOutTradeNo());
		WxPayOrderCloseResult wxPayOrderCloseResult;
		try {
			wxPayOrderCloseResult = wxService.closeOrder(request);
			log.info("{},wxPayOrderCloseResult: {}",wxPayOrderCloseResult);
			String returnCode = wxPayOrderCloseResult.getReturnCode();
			String resultCode = wxPayOrderCloseResult.getResultCode();
			// 处理微信返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode) && WxTradeStatus.SUCCESS.equals(resultCode)) {
				return Json.succ(oper, "订单关闭成功！");
			} else {
				return Json.fail(oper, wxPayOrderCloseResult.getReturnMsg());
			}
		}
		catch (WxPayException e) {
			e.printStackTrace();
		}
		return Json.succ(oper, "订单关闭成功!");
	}

	@GetMapping("/jsapiPay")
	public Json pay(HttpServletRequest request, String outTradeNo, String code, Integer totalAmount, String subject, String orgId, String channelId, String body, String describe) {
		String oper = "wxpay_jsapi";
		log.info("{}, body: {}", oper);
		Wrapper<PlatformBusinessRec> queryParams = new EntityWrapper<>();
		queryParams.eq("out_trade_no", outTradeNo);
		queryParams.eq("deleted", 0);
		PlatformBusinessRec oldBusinessRec = platformBusinessRecService.selectOne(queryParams);
		if (oldBusinessRec != null) {
			return Json.fail(oper, "该订单号已存在！");
		}
		WxPayProperties wxPayProperties = wxPayClient.getWxPayProperties(orgId);
		if (wxPayProperties == null) {
			return Json.fail(oper, "微信配置不存在！");
		}
		WxPayService wxService = wxPayClient.getWxService(orgId);
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}
		WxPayConfig wxPayConfig = wxService.getConfig();
		String openId = wxPayClient.getopendid(code, wxPayConfig);

		Map<String, Object> map;
		Map<String, Object> returnMap = new HashMap<>();
		String prepay_id;
		WxPlaceOrder wxPlaceOrder = new WxPlaceOrder();
		wxPlaceOrder.setAppid(Configure.APP_ID);
		wxPlaceOrder.setBody(body);
		wxPlaceOrder.setMch_id(Configure.PAY_ID);
		wxPlaceOrder.setNonce_str(UUID.randomUUID().toString().replaceAll("-", ""));
		wxPlaceOrder.setNotify_url(wxPayProperties.getNotifyUrl());
		wxPlaceOrder.setOpenid(openId);
		wxPlaceOrder.setOut_trade_no(outTradeNo);
		wxPlaceOrder.setSpbill_create_ip(IpUtil.getIpAddr(request));
		//		wxPlaceOrder.setTotal_fee(totalAmount);
		wxPlaceOrder.setTotal_fee(1);
		wxPlaceOrder.setTrade_type(WxPayConstants.TradeType.JSAPI);
		wxPlaceOrder.setSign(Signature.getSign(wxPlaceOrder));
		XStream xStream = new XStream(new StaxDriver(new NoNameCoder()));
		xStream.alias("xml", WxPlaceOrder.class);
		String xml = xStream.toXML(wxPlaceOrder);
		String result = CommondUtil.httpsRequest(Configure.WX_PlACE_ORDER, "GET", xml);
		log.info(result);
		returnMap.put("code", "-1");// 下单失败
		if (!"".equals(result)) {
			try {
				map = XMLParser.getMapFromXML(result);
				if (map.containsKey("prepay_id")) {
					PlatformBusinessRec businessRec = new PlatformBusinessRec();
					businessRec.setOrgId(orgId);
					businessRec.setChannelId(channelId);
					businessRec.setModeId(wxPayClient.getModeById(orgId).getId());
					businessRec.setRecType(Byte.valueOf("1"));
					businessRec.setOutTradeNo(outTradeNo);
					businessRec.setTotalFee(new BigDecimal(totalAmount));
					businessRec.setTradeDate(new Date());
					businessRec.setAccountFlag(Byte.valueOf("0"));
					businessRec.setAbnormalFlag(Byte.valueOf("0"));
					businessRec.setCreateDate(new Date());
					businessRec.setTradeType(WxPayConstants.TradeType.JSAPI);
					platformBusinessRecService.insert(businessRec);
					// 统一下单接口成功
					prepay_id = (String)map.get("prepay_id");
					// 签名 并返回前端
					wxPlaceOrder = new WxPlaceOrder();
					wxPlaceOrder.setAppid(Configure.APP_ID);
					wxPlaceOrder.setNonce_str(Util.uuid());
					wxPlaceOrder.setTimeStamp(System.currentTimeMillis() / 1000 + "");
					wxPlaceOrder.setPrepay_id(prepay_id);
					returnMap.put("nonce_str", wxPlaceOrder.getNonce_str());
					returnMap.put("appid", Configure.APP_ID);
					returnMap.put("timeStamp", wxPlaceOrder.getTimeStamp());
					returnMap.put("paySign", Signature.getSignPay(wxPlaceOrder));
					returnMap.put("prepay_id", prepay_id);
					returnMap.put("code", "1");// 下单成功
				}
			}
			catch (Exception e) {
			}
		}
		return Json.succ(oper).data("prepareId", returnMap.get("prepay_id")).data("paySign", returnMap.get("paySign")).data("appId", wxPayProperties.getAppId())
			.data("timeStamp", System.currentTimeMillis() / 1000 + "").data("nonceStr", returnMap.get("nonce_str"));
	}

	@PostMapping("/wxAppPay2")
	public Json wxPay2(@Valid WxPayAppProperties wxPayAppProperties, BindingResult bindingResult, HttpServletRequest request) throws WxPayException {
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail("wxpay", bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		WxPayProperties wxPayProperties = wxPayClient.getWxPayProperties(wxPayAppProperties.getOrgId());
		if (wxPayProperties == null) {
			return Json.fail("wxpay", "微信配置不存在！");
		}
		Map<String, String> map = new HashMap<>();
		try {
			Map<String, String> result = wXservice.dounifiedOrder(wxPayAppProperties, IpUtil.getIpAddr(request), wxPayProperties.getNotifyUrl());
			WxMD5Util md5Util = new WxMD5Util();
			//返回APP端的数据
			//参加调起支付的签名字段有且只能是6个，分别为appid、partnerid、prepayid、package、noncestr和timestamp，而且都必须是小写
			map.put("appid", result.get("appid"));
			map.put("partnerid", result.get("mch_id"));
			map.put("prepayid", result.get("prepay_id"));
			map.put("package", "Sign=WXPay");
			map.put("noncestr", result.get("nonce_str"));
			//单位为秒
			map.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
			map.put("sign", md5Util.getSign(map));

			PlatformBusinessRec businessRec = new PlatformBusinessRec();
			businessRec.setOrgId(wxPayAppProperties.getOrgId());
			businessRec.setChannelId(wxPayAppProperties.getChannelId());
			businessRec.setModeId(wxPayClient.getModeById(wxPayAppProperties.getOrgId()).getId());
			businessRec.setRecType(Byte.valueOf("1"));
			businessRec.setOutTradeNo(wxPayAppProperties.getOutTradeNo());
			businessRec.setTotalFee(new BigDecimal(wxPayAppProperties.getTotalAmount()));
			businessRec.setTradeDate(new Date());
			businessRec.setAccountFlag(Byte.valueOf("0"));
			businessRec.setAbnormalFlag(Byte.valueOf("0"));
			businessRec.setCreateDate(new Date());
			businessRec.setTradeType(WxPayConstants.TradeType.APP);
			businessRec.setDescribe(wxPayAppProperties.getBody());
			platformBusinessRecService.insert(businessRec);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return Json.succ("wxpay").data("result", map);
	}

	/**
	 * 微信H5统一下单(tradeType传MWEB)
	 * 微信APP统一下单(tradeType传APP)(详见https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)
	 * 在发起微信支付前，需要调用统一下单接口，获取"预支付交易会话标识"
	 * 接口地址：https://api.mch.weixin.qq.com/pay/unifiedorder
	 * <p>
	 * //	 * @param wxPayAppProperties 请求对象，注意一些参数如appid、mchid等不用设置，方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
	 *
	 * @return 预备交易单号
	 * @throws WxPayException
	 */
	@ApiOperation(value = "app支付", notes = "返回创建微信交易订单", httpMethod = "POST")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "渠道ID", name = "channelId", required = true, dataType = "String", example = "1034683401866588162"),
		@ApiImplicitParam(value = "系统订单号", name = "outTradeNo", required = true, dataType = "String", example = "1111111141111"),
		@ApiImplicitParam(value = "病人卡号", name = "cardNo", required = false, dataType = "String", example = "12345678", allowEmptyValue = true),
		@ApiImplicitParam(value = "病人姓名", name = "name", required = false, dataType = "String", example = "测试人1", allowEmptyValue = true),
		@ApiImplicitParam(value = "标题", name = "body", required = true, dataType = "String", example = "腾讯充值中心-QQ会员充值"),
		@ApiImplicitParam(value = "描述", name = "detail", required = true, dataType = "String", example = "测试描述"),
		@ApiImplicitParam(value = "交易类型", name = "tradeType", required = true, dataType = "String", example = "APP,MWEB"),
		@ApiImplicitParam(value = "订单总金额 单位为元，保留两位小数", name = "totalFee", required = true, dataType = "BigDecimal", example = "0.01"),
		@ApiImplicitParam(value = "商品ID 此id为二维码中包含的商品ID，商户自行定义", name = "productId", required = true, dataType = "String", example = "1111111111"),
		@ApiImplicitParam(value = "商户机具终端编号", name = "deviceInfo", required = false, example = ""), @ApiImplicitParam(value = "商户操作员编号", name = "operatorId", required = true, example = "111111111"),
		@ApiImplicitParam(value = "操作员姓名", name = "operatorName", required = true, dataType = "String", example = "操作员1"),
	})
	@PostMapping("/wxAppPay")
	public Json wxPay(@Valid WxPayAppProperties wxPayAppProperties, BindingResult bindingResult, HttpServletRequest request) throws WxPayException {
		String oper = "wxpay_app";
		log.info("{}, body: {}", oper, wxPayAppProperties);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}

		WxPayProperties wxPayProperties = wxPayClient.getWxPayProperties(wxPayAppProperties.getOrgId());
		if (wxPayProperties == null) {
			return Json.fail(oper, "微信配置不存在！");
		}
		WxPayService wxService = wxPayClient.getWxService(wxPayAppProperties.getOrgId());
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}
		String random32 = generateNonceStr();

		WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
		//		wxPayUnifiedOrderRequest.setAppid(wxPayProperties.getAppId());
		wxPayUnifiedOrderRequest.setBody(wxPayAppProperties.getBody());
		//		wxPayUnifiedOrderRequest.setNonceStr(random32);
		wxPayUnifiedOrderRequest.setOutTradeNo(wxPayAppProperties.getOutTradeNo());
		wxPayUnifiedOrderRequest.setNotifyUrl(wxPayProperties.getNotifyUrl());
		wxPayUnifiedOrderRequest.setTradeType(WxPayConstants.TradeType.APP);
		wxPayUnifiedOrderRequest.setSignType(WxPayConstants.SignType.MD5);
		wxPayUnifiedOrderRequest.setTotalFee(getTotalFee(wxPayAppProperties.getTotalAmount()));
		wxPayUnifiedOrderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));

		WxPayAppOrderResult wxPayUnifiedOrderResult;
		try {

			wxPayUnifiedOrderResult = wxService.createOrder(wxPayUnifiedOrderRequest);
			// 将支付记录保存到数据库
			PlatformBusinessRec businessRec = new PlatformBusinessRec();
			businessRec.setOrgId(wxPayAppProperties.getOrgId());
			businessRec.setChannelId(wxPayAppProperties.getChannelId());
			businessRec.setModeId(wxPayClient.getModeById(wxPayAppProperties.getOrgId()).getId());
			businessRec.setRecType(Byte.valueOf("1"));
			businessRec.setOutTradeNo(wxPayAppProperties.getOutTradeNo());
			businessRec.setTotalFee(new BigDecimal(wxPayAppProperties.getTotalAmount()));
			businessRec.setTradeDate(new Date());
			businessRec.setAccountFlag(Byte.valueOf("0"));
			businessRec.setAbnormalFlag(Byte.valueOf("0"));
			businessRec.setCreateDate(new Date());
			businessRec.setTradeType(WxPayConstants.TradeType.APP);
			businessRec.setDescribe(wxPayAppProperties.getBody());
			platformBusinessRecService.insert(businessRec);

		}
		catch (WxPayException e) {
			return Json.fail(oper, e.getErrCodeDes());
		}
		return Json.succ(oper).data("result", wxPayUnifiedOrderResult);
	}

	/**
	 * JSAPI统一下单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
	 * 在发起微信支付前，需要调用统一下单接口，获取"预支付交易会话标识"
	 * 接口地址：https://api.mch.weixin.qq.com/pay/unifiedorder
	 *
	 * @param request 请求对象，注意一些参数如appid、mchid等不用设置，方法内会自动从配置对象中获取到（前提是对应配置中已经设置）
	 */
	@ApiOperation(value = "扫码支付接口", notes = "商户系统先调用该接口在微信支付服务后台生成预支付交易单，返回正确的预支付交易会话标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。", httpMethod = "POST")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "渠道ID", name = "channelId", required = true, dataType = "String", example = "1034683401866588162"),
		@ApiImplicitParam(value = "系统订单号", name = "outTradeNo", required = true, dataType = "String", example = "1111111141111"),
		@ApiImplicitParam(value = "有效时间", name = "expireTime", required = false, dataType = "String", example = "15"),
		@ApiImplicitParam(value = "病人卡号", name = "cardNo", required = false, dataType = "String", example = "12345678", allowEmptyValue = true),
		@ApiImplicitParam(value = "病人姓名", name = "name", required = false, dataType = "String", example = "测试人1", allowEmptyValue = true),
		@ApiImplicitParam(value = "标题", name = "body", required = true, dataType = "String", example = "测试标题"),
		@ApiImplicitParam(value = "描述", name = "detail", required = true, dataType = "String", example = "测试描述"),
		@ApiImplicitParam(value = "订单总金额 单位为元，保留两位小数", name = "totalFee", required = true, dataType = "BigDecimal", example = "0.01"),
		@ApiImplicitParam(value = "商品ID 此id为二维码中包含的商品ID，商户自行定义", name = "productId", required = true, dataType = "String", example = "1111111111"),
		@ApiImplicitParam(value = "商户机具终端编号", name = "deviceInfo", required = false, example = ""), @ApiImplicitParam(value = "商户操作员编号", name = "operatorId", required = true, example = "111111111"),
		@ApiImplicitParam(value = "操作员姓名", name = "operatorName", required = true, dataType = "String", example = "操作员1"),
	})
	@PostMapping("/unifiedorder")
	public Json unifiedOrder(@Valid UnifiedOrderParams unifiedOrderParams, BindingResult bindingResult, HttpServletRequest request) throws WxPayException {
		String oper = "wxpay_scanpay";
		log.info("{}, body: {}", oper, unifiedOrderParams);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		String orgId = unifiedOrderParams.getOrgId();
		String channelId = unifiedOrderParams.getChannelId();
		String outTradeNo = unifiedOrderParams.getOutTradeNo();
		String cardNo = unifiedOrderParams.getCardNo();
		String name = unifiedOrderParams.getName();
		String operatorId = unifiedOrderParams.getOperatorId();
		String operatorName = unifiedOrderParams.getOperatorName();

		WxPayService wxService = wxPayClient.getWxService(orgId);
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}
		WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
		if (org.apache.commons.lang.StringUtils.isNotBlank(unifiedOrderParams.getExpireTime())) {
			wxPayUnifiedOrderRequest.setTimeExpire(unifiedOrderParams.getExpireTime());
		}
		wxPayUnifiedOrderRequest.setBody(unifiedOrderParams.getBody());
		wxPayUnifiedOrderRequest.setDetail(unifiedOrderParams.getDetail());
		wxPayUnifiedOrderRequest.setOutTradeNo(outTradeNo);
		wxPayUnifiedOrderRequest.setNotifyUrl(wxPayClient.getWxPayProperties(orgId).getNotifyUrl());
		wxPayUnifiedOrderRequest.setAttach(orgId);
		wxPayUnifiedOrderRequest.setTradeType("NATIVE");
		wxPayUnifiedOrderRequest.setProductId(unifiedOrderParams.getProductId());
		wxPayUnifiedOrderRequest.setTotalFee(getTotalFee(unifiedOrderParams.getTotalFee()));
		wxPayUnifiedOrderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request));
		String codeUrl;
		try {
			WxPayUnifiedOrderResult wxPayUnifiedOrderResult = wxService.unifiedOrder(wxPayUnifiedOrderRequest);
			String returnCode = wxPayUnifiedOrderResult.getReturnCode();
			String resultCode = wxPayUnifiedOrderResult.getResultCode();
			// 处理微信返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode)) {
				if (WxTradeStatus.SUCCESS.equals(resultCode)) {
					//获取二维码成功
					codeUrl = wxPayUnifiedOrderResult.getCodeURL();
					// 将支付记录保存到数据库
					PlatformBusinessRec businessRec = new PlatformBusinessRec();
					businessRec.setOrgId(orgId);
					businessRec.setChannelId(channelId);
					businessRec.setModeId(wxPayClient.getModeById(orgId).getId());
					businessRec.setRecType(Byte.valueOf("1"));
					businessRec.setOutTradeNo(outTradeNo);
					businessRec.setCardNo(cardNo);
					businessRec.setName(name);
					businessRec.setTotalFee(new BigDecimal(unifiedOrderParams.getTotalFee()).setScale(2, BigDecimal.ROUND_HALF_UP));
					businessRec.setTradeDate(new Date());
					businessRec.setAccountFlag(Byte.valueOf("0"));
					businessRec.setAbnormalFlag(Byte.valueOf("0"));
					businessRec.setCreateDate(new Date());
					businessRec.setOperatorId(operatorId);
					businessRec.setOperatorName(operatorName);
					platformBusinessRecService.insert(businessRec);

				} else {
					return Json.fail(oper, wxPayUnifiedOrderResult.getErrCodeDes());
				}
			} else {
				return Json.fail(oper, wxPayUnifiedOrderResult.getReturnMsg());
			}
		}
		catch (WxPayException e) {
			return Json.fail(oper, e.getErrCodeDes());
		}
		return Json.succ(oper).data("qr_code", codeUrl);
	}

	private int getTotalFee(String totalFee) {
		BigDecimal bd = new BigDecimal(totalFee).setScale(2, BigDecimal.ROUND_HALF_UP);
		return bd.multiply(new BigDecimal(100)).intValue();
	}

	/**
	 * 支付成功回调地址
	 *
	 * @param request
	 * @param response
	 * @throws Exception
	 */
	@ApiIgnore
	@PostMapping("/unifiedorder_notify")
	public String unifiedOrderNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 读取参数
		String message = "";
		InputStream inputStream = request.getInputStream();
		StringBuffer sb = new StringBuffer();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();
		String resXml = "";
		Wrapper<SysOrganization> queryParamse = new EntityWrapper<>();
		queryParamse.orderBy("sort_no", true);
		queryParamse.eq("deleted", 0);
		List<SysOrganization> sysOrganizationList = sysOrganizationService.selectList(queryParamse);
		for (SysOrganization sysOrganization : sysOrganizationList) {
			String orgId = sysOrganization.getId();
			WxPayService wxService = wxPayClient.getWxService(orgId);

			try {
				WxPayOrderNotifyResult wxPayOrderNotifyResult = wxService.parseOrderNotifyResult(sb.toString());
				if (WxTradeStatus.SUCCESS.equals(wxPayOrderNotifyResult.getReturnCode())) {
					if (WxTradeStatus.SUCCESS.equals(wxPayOrderNotifyResult.getResultCode())) {
						// 这里是支付成功
						String outTradeNo = wxPayOrderNotifyResult.getOutTradeNo();
						//在数据库中查找订单号对应的订单，并将其金额与数据库中的金额对比，若对不上，也为异常通知
						Wrapper<PlatformBusinessRec> queryParams = new EntityWrapper<>();
						queryParams.eq("out_trade_no", outTradeNo);
						queryParams.eq("deleted", 0);
						PlatformBusinessRec businessRec = platformBusinessRecService.selectOne(queryParams);
						if (businessRec != null) {
							if (businessRec.getTradeNo() == null || businessRec.getTradeNo().isEmpty()) {
								BigDecimal totalFee = businessRec.getTotalFee();
								BigDecimal totalFeeResult = new BigDecimal(wxPayOrderNotifyResult.getTotalFee()).multiply(new BigDecimal(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);
								if (totalFeeResult.compareTo(totalFee) == 0) {
									message = "SUCCESS";
									//成功 更新状态
									String tradeNo = wxPayOrderNotifyResult.getTransactionId();
									businessRec.setTradeNo(tradeNo);
									SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
									businessRec.setTradeDate(simpleDateFormat.parse(wxPayOrderNotifyResult.getTimeEnd()));
									businessRec.setTradeStatus(wxPayOrderNotifyResult.getResultCode());
									platformBusinessRecService.updateById(businessRec);
									resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
									//@TODO 更新HIS库状态,返回支付结果与tradeNo
									log.info("更新HIS库状态,返回支付结果与tradeNo");
									SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss ");
									String date = dateformat.format(businessRec.getTradeDate());
									webService.sendPost(sysOrganization.getNotifyUrl(),
										"outTradeNo=" + businessRec.getOutTradeNo() + "&tradeNo=" + tradeNo + "&totalFee=" + businessRec.getTotalFee() + "&tradeType=wx&tradeDate=" + date);
								} else {
									resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
									log.info("金额不符！");
								}
							} else {
								log.info("此单已处理！");
								resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
							}
						} else {
							log.info("此单不存在！");
							resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
						}
						break;
					} else {
						resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
					}
				} else {
					resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
				}
			}
			catch (WxPayException e) {
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
			}
		}
		BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
		out.write(resXml.getBytes());
		out.flush();
		out.close();
		return message;
	}

	/**
	 * <pre>
	 * 微信支付-申请退款
	 * 说明：因退款操作存在结果延时，需要等待微信通知结果
	 * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
	 * 接口链接：https://api.mch.weixin.qq.com/secapi/pay/refund
	 * </pre>
	 *
	 * @param wxRefundParams 请求对象
	 * @return 退款操作结果
	 */
	@ApiOperation(value = "微信退款接口", notes = "微信退款接口")
	@ApiImplicitParams({
		@ApiImplicitParam(value = "机构ID", name = "orgId", required = true, dataType = "String", example = "1032882050992017410"),
		@ApiImplicitParam(value = "渠道ID", name = "channelId", required = true, dataType = "String", example = "1034683401866588162"),
		@ApiImplicitParam(value = "原系统订单号", name = "outTradeNo", required = true, dataType = "String", example = "1111111141111"),
		@ApiImplicitParam(value = "系统退款单号", name = "outRefundNo", required = true, dataType = "String", example = "1111111141122"),
		@ApiImplicitParam(value = "订单总金额,单位为元，支持两位小数", name = "totalFee", required = true, dataType = "String", example = "0.01"),
		@ApiImplicitParam(value = "退款总金额,该金额不能大于订单金额,单位为元，支持两位小数", name = "refundFee", required = true, dataType = "String", example = "0.01"),
		@ApiImplicitParam(value = "退款理由", name = "refundReason", required = true, dataType = "String", example = "正常退款"),
		@ApiImplicitParam(value = "商户操作员编号", name = "operatorId", required = true, example = "111111111"),
		@ApiImplicitParam(value = "操作员姓名", name = "operatorName", required = true, dataType = "String", example = "操作员1"),
	})
	@PostMapping("/refund")
	public Json refund(@Valid WxRefundParams wxRefundParams, BindingResult bindingResult) {
		String oper = "weixin_refund";
		log.info("{}, body: {}", oper, wxRefundParams);
		if (bindingResult.getErrorCount() > 0) {
			return Json.fail(oper, bindingResult.getFieldErrors().get(0).getDefaultMessage());
		}
		String orgId = wxRefundParams.getOrgId();
		String channelId = wxRefundParams.getChannelId();
		String outTradeNo = wxRefundParams.getOutTradeNo();
		String outRefundNo = wxRefundParams.getOutRefundNo();
		String totalFee = wxRefundParams.getTotalFee();
		String refundFee = wxRefundParams.getRefundFee();
		String refundReason = wxRefundParams.getRefundReason();
		String operatorId = wxRefundParams.getOperatorId();
		String operatorName = wxRefundParams.getOperatorName();

		Wrapper<PlatformBusinessRec> queryParams = new EntityWrapper<>();
		queryParams.eq("out_trade_no", outTradeNo);
		queryParams.eq("org_id", orgId);
		queryParams.eq("deleted", 0);
		PlatformBusinessRec oldBusinessRec = platformBusinessRecService.selectOne(queryParams);
		if (oldBusinessRec == null) {
			return Json.fail(oper).data("订单不存在");
		}
		Wrapper<PlatformBusinessRec> queryRefundParams = new EntityWrapper<>();
		queryRefundParams.eq("out_request_no", outRefundNo);
		queryRefundParams.eq("org_id", orgId);
		queryRefundParams.eq("deleted", 0);
		PlatformBusinessRec oldRefundBusinessRec = platformBusinessRecService.selectOne(queryRefundParams);
		if (oldRefundBusinessRec != null) {
			return Json.fail(oper).data("退款记录已存在");
		}
		WxPayService wxService = wxPayClient.getWxService(orgId);
		if (wxService == null) {
			return Json.fail(oper, "本机构微信未配置或配置不正确！");
		}
		WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
		wxPayRefundRequest.setOutTradeNo(outTradeNo);
		wxPayRefundRequest.setOutRefundNo(outRefundNo);
		BigDecimal totalFeeBd;
		Integer totalFeeInt;
		BigDecimal refundFeeBd;
		Integer refundFeeInt;
		try {
			totalFeeBd = new BigDecimal(totalFee).setScale(2, BigDecimal.ROUND_HALF_UP);
			totalFeeInt = totalFeeBd.multiply(new BigDecimal(100)).intValue();
		}
		catch (Exception e) {
			return Json.fail(oper, "totalFee格式不正确！");
		}
		try {
			refundFeeBd = new BigDecimal(refundFee).setScale(2, BigDecimal.ROUND_HALF_UP);
			refundFeeInt = refundFeeBd.multiply(new BigDecimal(100)).intValue();
		}
		catch (Exception e) {
			return Json.fail(oper, "refundFee格式不正确！");
		}
		wxPayRefundRequest.setTotalFee(totalFeeInt);
		wxPayRefundRequest.setRefundFee(refundFeeInt);
		wxPayRefundRequest.setRefundDesc(refundReason);
		wxPayRefundRequest.setNotifyUrl(wxPayClient.getWxPayProperties(orgId).getRefundNotifyUrl());
		try {
			WxPayRefundResult refundResult = wxService.refund(wxPayRefundRequest);
			String returnCode = refundResult.getReturnCode();
			String resultCode = refundResult.getResultCode();
			// 处理微信返回结果
			if (WxTradeStatus.SUCCESS.equals(returnCode)) {
				if (WxTradeStatus.SUCCESS.equals(resultCode)) {
					//20s后查询退款状态
					scheduledThreadPoolExecutor.schedule(() -> {
						queryMyRefundStatus(wxRefundParams.getOrgId(), wxRefundParams.getOutRefundNo());
					}, 20, TimeUnit.SECONDS);
					// 将退款记录保存到数据库
					PlatformBusinessRec businessRec = new PlatformBusinessRec();
					businessRec.setOrgId(orgId);
					businessRec.setChannelId(channelId);
					businessRec.setModeId(wxPayClient.getModeById(orgId).getId());
					businessRec.setRecType(Byte.valueOf("2"));
					//微信退款单号只在退款成功时记录
					businessRec.setOutRequestNo(outRefundNo);
					businessRec.setOutTradeNo(outTradeNo);
					businessRec.setCardNo(oldBusinessRec.getCardNo());
					businessRec.setName(oldBusinessRec.getName());
					businessRec.setTotalFee(refundFeeBd);
					businessRec.setTradeDate(new Date());
					businessRec.setAccountFlag(Byte.valueOf("0"));
					businessRec.setAbnormalFlag(Byte.valueOf("0"));
					businessRec.setCreateDate(new Date());
					businessRec.setOperatorId(operatorId);
					businessRec.setOperatorName(operatorName);
					platformBusinessRecService.insert(businessRec);

				} else {
					return Json.fail(oper, refundResult.getErrCodeDes());
				}
			} else {
				return Json.fail(oper, refundResult.getReturnMsg());
			}
		}
		catch (WxPayException e) {
			return Json.fail(oper, e.getErrCodeDes());
		}
		catch (Exception e) {
			return Json.fail(oper, e.getMessage());
		}
		return Json.succ(oper, "微信退款中");
	}

	@ApiOperation(value = "微信退款状态查询", notes = "查询接口")
	@PostMapping("/queryWxRefundStatus")
	public Object queryMyRefundStatus(String orgId, String outRefundNo) {
		String oper = "wxRefund_query";
		log.info("{退款回调}, body: {}", oper, orgId, outRefundNo);
		String values = "";
		WxPayService wxService = wxPayClient.getWxService(orgId);
		try {
			WxPayRefundQueryResult wxPayRefundQueryResult = wxService.refundQuery("", "", outRefundNo, "");
			String returnCode = wxPayRefundQueryResult.getReturnCode();
			if (WxTradeStatus.SUCCESS.equals(returnCode) && WxTradeStatus.SUCCESS.equals(wxPayRefundQueryResult.getResultCode())) {
				List<WxPayRefundQueryResult.RefundRecord> refundRecords = wxPayRefundQueryResult.getRefundRecords();
				WxPayRefundQueryResult.RefundRecord refundRecord = refundRecords.get(0);
				switch (refundRecord.getRefundStatus()) {
					case WxTradeStatus.SUCCESS:
						System.out.println("退款成功");
						values = "REFUND_SUCCESS";
						//在数据库中查找订单号对应的订单
						Wrapper<PlatformBusinessRec> queryParams = new EntityWrapper<>();
						queryParams.eq("out_request_no", outRefundNo);
						queryParams.eq("deleted", 0);
						PlatformBusinessRec businessRec = platformBusinessRecService.selectOne(queryParams);
						if (businessRec != null) {
							if (businessRec.getTradeNo() == null || businessRec.equals("")) {
								//已退款 更新状态
								String tradeNo = refundRecord.getRefundId();
								businessRec.setTradeNo(tradeNo);
								SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
								Date date = null;
								try {
									date = simpleDateFormat.parse(refundRecord.getRefundSuccessTime());
								}
								catch (ParseException e) {
									e.printStackTrace();
								}
								businessRec.setTradeDate(date);
								businessRec.setTradeStatus(refundRecord.getRefundStatus());
								platformBusinessRecService.updateById(businessRec);
							} else {
								log.info("此单已处理！");
							}
						}
						break;
					case WxTradeStatus.REFUNDCLOSE:
						values = "REFUND_CLOSE";
						break;
					case WxTradeStatus.PROCESSING:
						//再次查询
						scheduledThreadPoolExecutor.schedule(() -> {
							queryMyRefundStatus(orgId, outRefundNo);
						}, 45, TimeUnit.SECONDS);
						break;
					case WxTradeStatus.CHANGE:
						values = "REFUND_CHARGE";
						break;
					default:
				}
			} else {
				scheduledThreadPoolExecutor.schedule(() -> {
					queryMyRefundStatus(orgId, outRefundNo);
				}, 45, TimeUnit.SECONDS);
			}
		}
		catch (WxPayException e) {
			values = "QUERY_FAILURE";
			e.getErrCode();
		}
		return Json.succ(true, oper, values, "");
	}

	/**
	 * method: refundNotify
	 *
	 * @Description: 退款回调方法
	 * @param: [request, response]
	 * @return: void
	 * @author: yh
	 * @date: 2018/9/2 18:32
	 */
	@ApiIgnore
	@PostMapping("/refund_notify")
	public String refundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 读取参数
		String message = "";
		InputStream inputStream = request.getInputStream();
		StringBuffer sb = new StringBuffer();
		String s;
		BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
		while ((s = in.readLine()) != null) {
			sb.append(s);
		}
		in.close();
		inputStream.close();

		String resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
		Wrapper<SysOrganization> queryParamse = new EntityWrapper<>();
		queryParamse.orderBy("sort_no", true);
		queryParamse.eq("deleted", 0);
		List<SysOrganization> sysOrganizationList = sysOrganizationService.selectList(queryParamse);
		for (SysOrganization sysOrganization : sysOrganizationList) {
			String orgId = sysOrganization.getId();
			WxPayService wxService = wxPayClient.getWxService(orgId);
			if (wxService == null) {
				continue;
			}
			try {
				WxPayRefundNotifyResult wxPayRefundNotifyResult = wxService.parseRefundNotifyResult(sb.toString());
				if (WxTradeStatus.SUCCESS.equals(wxPayRefundNotifyResult.getReturnCode())) {
					//支付宝返回的结果可能是null或者是SUCCESS  所以取消判断ResultCode，直接通过RefundStatus来判断
					String refundStatus = wxPayRefundNotifyResult.getReqInfo().getRefundStatus();
					if (WxTradeStatus.SUCCESS.equals(refundStatus)) {
						// 这里是退款成功
						String outRefundNo = wxPayRefundNotifyResult.getReqInfo().getOutRefundNo();
						//在数据库中查找订单号对应的订单
						Wrapper<PlatformBusinessRec> queryParams = new EntityWrapper<>();
						queryParams.eq("out_request_no", outRefundNo);
						queryParams.eq("rec_type", "2");
						queryParams.eq("deleted", 0);
						PlatformBusinessRec businessRec = platformBusinessRecService.selectOne(queryParams);
						if (businessRec != null) {
							if (businessRec.getTradeNo() == null || businessRec.equals("")) {
								//已退款 更新状态
								String tradeNo = wxPayRefundNotifyResult.getReqInfo().getRefundId();
								businessRec.setTradeNo(tradeNo);
								SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
								businessRec.setTradeDate(simpleDateFormat.parse(wxPayRefundNotifyResult.getReqInfo().getSuccessTime()));
								businessRec.setTradeStatus(wxPayRefundNotifyResult.getReqInfo().getRefundStatus());
								platformBusinessRecService.updateById(businessRec);
								message = "SUCCESS";
								resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
								//@TODO 更新HIS库状态,返回退款结果信息
							} else {
								log.info("此单已处理！");
								resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>" + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
							}
						}
					}
				}
			}
			catch (WxPayException e) {
				e.printStackTrace();
				resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
			}
		}
		BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
		out.write(resXml.getBytes());
		out.flush();
		out.close();
		return message;
	}
	/**
	 * <pre>
	 * 微信支付-查询退款
	 * 应用场景：
	 *  提交退款申请后，通过调用该接口查询退款状态。退款有一定延时，用零钱支付的退款20分钟内到账，
	 *  银行卡支付的退款3个工作日后重新查询退款状态。
	 * 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
	 * 接口链接：https://api.mch.weixin.qq.com/pay/refundquery
	 * </pre>
	 * 以下四个参数四选一
	 *
	 * @param transactionId 微信订单号
	 * @param outTradeNo    商户订单号
	 * @param outRefundNo   商户退款单号
	 * @param refundId      微信退款单号
	 * @return 退款信息
	 */
	//	    @GetMapping("/refundQuery")
	//	    public WxPayRefundQueryResult refundQuery(
	//	        @RequestParam(required = false) String transactionId,
	//	        @RequestParam(required = false) String outTradeNo,
	//	        @RequestParam(required = false) String outRefundNo,
	//	        @RequestParam(required = false) String refundId) throws WxPayException {
	//	        return this.wxService.refundQuery(transactionId, outTradeNo, outRefundNo, refundId);
	//	    }
	//
	//	    public WxPayRefundQueryResult refundQuery(WxPayRefundQueryRequest wxPayRefundQueryRequest) throws WxPayException {
	//	        return null;
	//	    }

	/**
	 *  此方法需要改造，根据实际需要返回com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse对象
	 */
	//    @PostMapping("/parseOrderNotifyResult")
	//    public WxPayOrderNotifyResult parseOrderNotifyResult(@RequestBody String xmlData) throws WxPayException {
	//        return this.wxService.parseOrderNotifyResult(xmlData);
	//    }

	/**
	 *  此方法需要改造，根据实际需要返回com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse对象
	 */
	//    @PostMapping("/parseRefundNotifyResult")
	//    public WxPayRefundNotifyResult parseRefundNotifyResult(@RequestBody String xmlData) throws WxPayException {
	//        return this.wxService.parseRefundNotifyResult(xmlData);
	//    }

	/**
	 *  此方法需要改造，根据实际需要返回所需对象
	 */
	//    @PostMapping("/parseScanPayNotifyResult")
	//    public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData) throws WxPayException {
	//        return this.wxService.parseScanPayNotifyResult(xmlData);
	//    }

	/**
	 * <pre>
	 * 扫码支付模式一生成二维码的方法
	 * 二维码中的内容为链接，形式为：
	 * weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
	 * 其中XXXXX为商户需要填写的内容，商户将该链接生成二维码，如需要打印发布二维码，需要采用此格式。商户可调用第三方库生成二维码图片。
	 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
	 * </pre>
	 *
	 * @param productId  产品Id
	 * @param logoFile   商户logo图片的文件对象，可以为空
	 * @param sideLength 要生成的二维码的边长，如果为空，则取默认值400
	 * @return 生成的二维码的字节数组
	 */
	//	public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) {
	//		return this.wxService.createScanPayQrcodeMode1(productId, logoFile, sideLength);
	//	}

	/**
	 * <pre>
	 * 扫码支付模式一生成二维码的方法
	 * 二维码中的内容为链接，形式为：
	 * weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
	 * 其中XXXXX为商户需要填写的内容，商户将该链接生成二维码，如需要打印发布二维码，需要采用此格式。商户可调用第三方库生成二维码图片。
	 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
	 * </pre>
	 *
	 * @param productId 产品Id
	 * @return 生成的二维码URL连接
	 */
	//	public String createScanPayQrcodeMode1(String productId) {
	//		return this.wxService.createScanPayQrcodeMode1(productId);
	//	}

	/**
	 * <pre>
	 * 扫码支付模式二生成二维码的方法
	 * 对应链接格式：weixin：//wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
	 * 该模式链接较短，生成的二维码打印到结账小票上的识别率较高。
	 * 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
	 * </pre>
	 *
	 * @param codeUrl    微信返回的交易会话的二维码链接
	 * @param logoFile   商户logo图片的文件对象，可以为空
	 * @param sideLength 要生成的二维码的边长，如果为空，则取默认值400
	 * @return 生成的二维码的字节数组
	 */
	//	public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) {
	//		return this.wxService.createScanPayQrcodeMode2(codeUrl, logoFile, sideLength);
	//	}

	/**
	 * <pre>
	 * 下载对账单
	 * 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致，通过对账单核对后可校正支付状态。
	 * 注意：
	 * 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中，跟原支付单订单号一致，bill_type为REVOKED；
	 * 2、微信在次日9点启动生成前一天的对账单，建议商户10点后再获取；
	 * 3、对账单中涉及金额的字段单位为“元”。
	 * 4、对账单接口只能下载三个月以内的账单。
	 * 接口链接：https://api.mch.weixin.qq.com/pay/downloadbill
	 * 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
	 * </pre>
	 *
	 * @param billDate   对账单日期 bill_date	下载对账单的日期，格式：20140603
	 * @param billType   账单类型	bill_type	ALL，返回当日所有订单信息，默认值，SUCCESS，返回当日成功支付的订单，REFUND，返回当日退款订单
	 * @param tarType    压缩账单	tar_type	非必传参数，固定值：GZIP，返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
	 * @param deviceInfo 设备号	device_info	非必传参数，终端设备号
	 * @return 保存到本地的临时文件
	 */
	//    @GetMapping("/downloadBill/{billDate}/{billType}/{tarType}/{deviceInfo}")
	//    public WxPayBillResult downloadBill(
	//        @PathVariable String billDate, @PathVariable String billType, @PathVariable String tarType, @PathVariable String deviceInfo) throws WxPayException {
	//        return this.wxService.downloadBill(billDate, billType, tarType, deviceInfo);
	//    }
	//
	//    public WxPayBillResult downloadBill(WxPayDownloadBillRequest wxPayDownloadBillRequest) throws WxPayException {
	//        return null;
	//    }

	/**
	 * <pre>
	 * 撤销订单API
	 * 文档地址：https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_11&index=3
	 * 应用场景：
	 *  支付交易返回失败或支付系统超时，调用该接口撤销交易。如果此订单用户支付失败，微信支付系统会将此订单关闭；如果用户支付成功，微信支付系统会将此订单资金退还给用户。
	 *  注意：7天以内的交易单可调用撤销，其他正常支付的单如需实现相同功能请调用申请退款API。提交支付交易后调用【查询订单API】，没有明确的支付结果再调用【撤销订单API】。
	 *  调用支付接口后请勿立即调用撤销订单API，建议支付后至少15s后再调用撤销订单接口。
	 *  接口链接 ：https://api.mch.weixin.qq.com/secapi/pay/reverse
	 *  是否需要证书：请求需要双向证书。
	 * </pre>
	 */
	//    @PostMapping("/reverseOrder")
	//    public WxPayOrderReverseResult reverseOrder(@RequestBody WxPayOrderReverseRequest request) throws WxPayException {
	//        return this.wxService.reverseOrder(request);
	//    }
	//
	//    @GetMapping("/getSandboxSignKey")
	//    public String getSandboxSignKey() throws WxPayException {
	//        return this.wxService.getSandboxSignKey();
	//    }
	//
	//    @PostMapping("/sendCoupon")
	//    public WxPayCouponSendResult sendCoupon(@RequestBody WxPayCouponSendRequest request) throws WxPayException {
	//        return this.wxService.sendCoupon(request);
	//    }
	//
	//    @PostMapping("/queryCouponStock")
	//    public WxPayCouponStockQueryResult queryCouponStock(@RequestBody WxPayCouponStockQueryRequest request) throws WxPayException {
	//        return this.wxService.queryCouponStock(request);
	//    }
	//
	//    @PostMapping("/queryCouponInfo")
	//    public WxPayCouponInfoQueryResult queryCouponInfo(@RequestBody WxPayCouponInfoQueryRequest request) throws WxPayException {
	//        return this.wxService.queryCouponInfo(request);
	//    }
	//
	//    @PostMapping("/queryComment")
	//    public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException {
	//        return this.queryComment(beginDate, endDate, offset, limit);
	//    }

	public static class CommondUtil {
		private static Logger log = LoggerFactory.getLogger(CommondUtil.class);

		public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
			StringBuffer buffer = null;
			try {
				// 创建SSLContext对象，并使用我们指定的信任管理器初始化
				SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
				sslContext.init(null, null, new java.security.SecureRandom());
				// 从上述SSLContext对象中得到SSLSocketFactory对象
				SSLSocketFactory ssf = sslContext.getSocketFactory();
				URL url = new URL(requestUrl);
				HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
				conn.setSSLSocketFactory(ssf);
				conn.setDoOutput(true);
				conn.setDoInput(true);
				conn.setUseCaches(false);
				// 设置请求方式（GET/POST）
				conn.setRequestMethod(requestMethod);
				// 当outputStr不为null时向输出流写数据
				if (null != outputStr) {
					OutputStream outputStream = conn.getOutputStream();
					// 注意编码格式
					outputStream.write(outputStr.getBytes("UTF-8"));
					outputStream.close();
				}
				// 从输入流读取返回内容
				InputStream inputStream = conn.getInputStream();
				InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
				BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
				String str = null;
				buffer = new StringBuffer();
				while ((str = bufferedReader.readLine()) != null) {
					buffer.append(str);
				}
				// 释放资源
				bufferedReader.close();
				inputStreamReader.close();
				inputStream.close();
				inputStream = null;
				conn.disconnect();
				//jsonObject = new JSONObject(buffer.toString());
			}
			catch (ConnectException ce) {
				log.error("连接服务器错误:" + ce.getMessage());
			}
			catch (Exception e) {
				log.error("创建ssl失败:" + e.getMessage());
			}
			return buffer.toString();
		}
	}
}

